using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Microblaze.Simulator.Engine;

namespace Weazel.Microblaze.Simulator.Components.Microblaze.Instructions
{
    /// <summary>
    /// Branch Immediate if Greater Than
    /// </summary>
    public class Bgti
      : ConditionalBranchInstruction
    {
        private enum BgtiInstructionKind
        {
            None,   // error
            bgti,   // branch immediate if Greater Than
            bgtid   // branch immediate if Greater Than with Delay
        }

        private BgtiInstructionKind kind;

        public override int CycleCount
        {
            get
            {
                if (BranchStatus == BranchInstructionCycleCountStatus.BranchTaken)
                    return 1;
                else
                    return kind == BgtiInstructionKind.bgtid ? 2 : 3;
            }
        }

        public Bgti()
            : base("bgti")
        {
        }

        public override void Set(uint address, uint value)
        {
            base.Set(address, value);

            kind =
              (DestinationRegister == 0x04) ? BgtiInstructionKind.bgti :
              (DestinationRegister == 0x14) ? BgtiInstructionKind.bgtid :
              BgtiInstructionKind.None;

            if (kind == BgtiInstructionKind.None)
                throw new UnknownInstructionException(value);
        }

        /// <summary>
        /// Branch if rA is greater than 0, to the instruction located in the offset 
        /// value of IMM. The target of the branch will be the instruction at address 
        /// PC + IMM. 
        /// The mnemonic bgtid will set the D bit. The D bit determines whether there 
        /// is a branch delay slot or not. If the D bit is set, it means that there 
        /// is a delay slot and the instruction following the branch (i.e. in the 
        /// branch delay slot) is allowed to complete execution before executing the 
        /// target instruction. If the D bit is not set, it means that there is no 
        /// delay slot, so the instruction to be executed after the branch is the 
        /// target instruction.
        /// </summary>    
        public override void Execute(MicroblazeComponent MicroblazeComponent)
        {
            // note use of int for comparison
            int sa = (int)MicroblazeComponent.ReadRegister(SourceRegisterA);

            if (sa > 0)
            {
                MicroblazeComponent.Pc = MicroblazeComponent.Pc + GetImmediateValue(MicroblazeComponent);
                BranchStatus = BranchInstructionCycleCountStatus.BranchTaken;

                if (kind == BgtiInstructionKind.bgtid)
                    MicroblazeComponent.DelayedBranchActive = true;
            }
            else
            {
                MicroblazeComponent.Pc += 4;
                BranchStatus = BranchInstructionCycleCountStatus.BranchNotTaken;
            }
        }

        public override string ToString()
        {
            return string.Format("{0} r{1}, {2}",
              kind,
              SourceRegisterA,
              ImmediateValue
            );
        }
    }
}
